package org.manon.json;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.SoftReference;
import java.util.List;

import org.manon.json.filter.Filter;
import org.manon.json.io.InputReader;
import org.manon.json.io.Serializer;
import org.manon.json.io.UTF8Input;

/**
 * @author <a href="mailto:jacques.militello@gmail.com">Jacques Militello</a>
 */
final class JSONImpl implements JSON {

	private final JSONFactory _factory;
	
	private final ThreadLocal<SoftReference<InputReader>> _inputs = new ThreadLocal<SoftReference<InputReader>>() {

		/**
		 * @see java.lang.ThreadLocal#initialValue()
		 */
		@Override
		protected SoftReference<InputReader> initialValue() {
			return new SoftReference<InputReader>(new UTF8Input());
		}
		
	};
	
	JSONImpl(JSONFactory jsonFactory) {
		_factory = jsonFactory;
	}
	
	/**
	 * @see org.manon.json.JSON#serialize(java.lang.Object, java.io.OutputStream, org.manon.json.filter.Filter)
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public <T> void serialize(T pojo, OutputStream os, Filter filter) throws IOException {
		
		if (pojo == null) {
			os.write(JSONConstants.EMPTY_OBJECT,0,2);
		}
		
		final Serializer serializer =_factory.getSerialiser(pojo.getClass());
		
		if (serializer == null) {
			throw new JSONException("No serializer for Class [" + pojo.getClass() + "]");
		}
		
		serializer.serialize(os, pojo, filter);
	}

	
	
	/**
	 * @see org.manon.json.JSON#serialize(java.util.List, java.io.OutputStream, org.manon.json.filter.Filter)
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public <T> void serialize(List<T> list, OutputStream os, Filter filter) throws IOException {
		
		if (list == null || list.isEmpty()) {
			os.write(JSONConstants.EMPTY_ARRAY,0,2);
			return;
		}
		
		final Serializer serializer = _factory.getSerialiser(list.get(0).getClass());
		
		if (serializer == null) {
			throw new JSONException("No serializer for Class [" + list.get(0).getClass() + "]");
		}
		
		os.write(JSONConstants.ARRAY_START,0,1);
		
		for (int i = 0, n = list.size() ; i < n ; i++) {
			serializer.serialize(os, list.get(i), filter);
			if (i + 1 < n) {
				os.write(JSONConstants.COMMA,0,1);		
			}
		}
		
		os.write(JSONConstants.ARRAY_END,0,1);
	}

	/**
	 * @see org.manon.json.JSON#deserialize(java.lang.String, java.io.InputStream)
	 */
	@SuppressWarnings({ "unchecked" })
	public <T> T deserialize(Class<T> pojo, InputStream is) throws IOException {
		InputReader input =  _inputs.get().get();
		input.setInputStream(is);
		return (T) input.read(_factory.getDeserializer(pojo));
	}
	
	
}
